
//using OpenTK;
//using OpenTK.Graphics.ES20;
//using SharpDepend.Datatypes;
//using System;
//using System.Collections.Generic;

//namespace ZquenceStudio3_SharedClasses
//{

//    class OpenGLRendererShared
//    {
//        int pgmID;
//        int vsID;
//        int fsID;

//        int attribute_vpos;
//        int attribute_texcoord;
//        int attribute_vcol;
//        int uniform_mview;
//        int mytexture;

//        int vbo_position;
//        int vbo_texcoord;
//        int vbo_color;
//        int vbo_mview;

//        Texture defaultTexture;

//        Matrix4[] mviewdata;
//        private int ibo_elements;
//        internal Dictionary<Texture, int> textures = new Dictionary<Texture, int>();
//        internal Dictionary<Texture, Texture> textures_rescaled = new Dictionary<Texture, Texture>();

//        FastStructList<float> texcoords = new FastStructList<float>();
//        FastStructList<float> vertdata = new FastStructList<float>();
//        FastStructList<float> coldata = new FastStructList<float>();
//        FastStructList<ushort> inds = new FastStructList<ushort>();

//        private bool mHasInit;

//        List<RectangleSpriteBatchItem> m_spriteBatchItems = new List<RectangleSpriteBatchItem>();
//        List<RectangleSpriteBatchItem> m_spriteBatchItemsOld = new List<RectangleSpriteBatchItem>();

//        List<LineSpriteBatchItem> m_spriteBatchItems_line = new List<LineSpriteBatchItem>();
//        List<LineSpriteBatchItem> m_spriteBatchItemsOld_line = new List<LineSpriteBatchItem>();

//        List<RectangleTrianglesBatchItem> m_spriteBatchItems_triangles = new List<RectangleTrianglesBatchItem>();
//        List<RectangleTrianglesBatchItem> m_spriteBatchItemsOld_triangles = new List<RectangleTrianglesBatchItem>();

//        internal readonly List<BatchItem> mReadyItems = new List<BatchItem>();

//        void CheckGLError()
//        {
//            var error = GL.GetError();
//            if (error != All.NoError)
//            {
//                global::Android.Util.Log.Error("OpenGL", "OpenGL Error: " + error.ToString());
//            }
//        }

//        public void Log(string log)
//        {
//            global::Android.Util.Log.Error("OpenGL", "OpenGL: " + log);
//        }

//        /// <summary>
//        ///  Reference: http://stackoverflow.com/questions/5422523/how-to-draw-a-texture-into-a-quad-with-opengl-es-2
//        ///  Reference: http://gamedev.stackexchange.com/questions/4309/opengl-es-2-0-setting-up-2d-projection/4326#4326
//        /// </summary>
//        public void InitialiseData(float width, float height, float dpiScale)
//        {
//            InitOpenGL(width, height, dpiScale);
//            Log("InitOpenGL(" + width + ", " + height + ")");

//            string vShader =
//@"
//            attribute vec2 v_coord;
//            attribute vec4 v_color;
//            attribute vec2 v_texcoord;
            
//            varying vec4 f_color;
//            varying vec2 f_texcoord;
            
//            uniform mat4 mvp;
            
//            void main()
//            {
//            	gl_Position = mvp * vec4(v_coord,1.0,1.0);
//                f_color = v_color;
//            	f_texcoord = v_texcoord;
//            }							
//            ".Replace("\r", "");



//            string fShader =
//@"precision mediump float;
//            varying vec2 f_texcoord;
//            varying vec4 f_color;
            
//            uniform sampler2D mytexture;
            
//            void main(void)
//            {
//            	gl_FragColor = texture2D(mytexture, f_texcoord) * f_color;
//            }														
//            ".Replace("\r", "");

//            // =====================================================
//            pgmID = GL.CreateProgram();
//            CheckGLError();
//            Log("pgmID: " + pgmID);

//            int vertexShader;
//            LoadShader(vShader, All.VertexShader, pgmID, out vertexShader);
//            Log("vertexShader: " + vertexShader);

//            int pixelShader;
//            LoadShader(fShader, All.FragmentShader, pgmID, out pixelShader);
//            Log("pixelShader: " + pixelShader);

//            GL.LinkProgram(pgmID);
//            CheckGLError();

//            int length = 0;
//            System.Text.StringBuilder sb = new System.Text.StringBuilder();
//            GL.GetProgramInfoLog(pgmID, 1, out length, sb);

//            attribute_vpos = GL.GetAttribLocation(pgmID, "v_coord");
//            Log("attribute_vpos: " + attribute_vpos);
//            CheckGLError();
//            attribute_vcol = GL.GetAttribLocation(pgmID, "v_color");
//            Log("attribute_vcol: " + attribute_vcol);
//            CheckGLError();
//            uniform_mview = GL.GetUniformLocation(pgmID, "mvp");
//            Log("uniform_mview: " + uniform_mview);
//            CheckGLError();

//            // TODO: Nu fungerar OpenGL med texture, testa i Mac, linux och android :)

//            attribute_texcoord = GL.GetAttribLocation(pgmID, "v_texcoord");
//            Log("attribute_texcoord: " + attribute_texcoord);
//            CheckGLError();
//            mytexture = GL.GetUniformLocation(pgmID, "mytexture");
//            Log("mytexture: " + mytexture);
//            CheckGLError();
//            //text = GL.GetProgramInfoLog(pgmID);
//            var error = GL.GetError();
//            if (attribute_vpos == -1 || attribute_vcol == -1 || uniform_mview == -1)
//            {
//                //Console.WriteLine("Error binding attributes");
//            }

//            GL.GenBuffers(1, out vbo_position);
//            Log("vbo_position: " + vbo_position);
//            GL.GenBuffers(1, out vbo_texcoord);
//            Log("vbo_texcoord: " + vbo_texcoord);
//            GL.GenBuffers(1, out vbo_color);
//            Log("vbo_color: " + vbo_color);
//            GL.GenBuffers(1, out vbo_mview);
//            Log("vbo_mview: " + vbo_mview);
//            CheckGLError();

//            GL.GenBuffers(1, out ibo_elements);
//            Log("ibo_elements: " + ibo_elements);
//            CheckGLError();

//            defaultTexture = new Texture(1, 1);
//            defaultTexture.Data[0] = -1;
//            AddTextureToOpenGL(defaultTexture);

//            UpdateViewport();
//            Log("UpdateViewport()");
//            CheckGLError();
//        }

//        public void InitOpenGL(double width, double height, double dpiScale)
//        {
//            RenderWidth = (float)width;
//            RenderHeight = (float)height;

//            //GL.ShadeModel(ShadingModel.Smooth);							    // Enable Smooth Shading
//            GL.ClearDepth(1.0f);									        // Depth Buffer Setup
//            GL.Enable(All.DepthTest);							        // Enables Depth Testing
//            GL.DepthFunc(All.Lequal);								// The Type Of Depth Testing To Do
//            //GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);	// Really Nice Perspective Calculations
//            CheckGLError();

//            GL.BlendFunc(All.SrcAlpha, All.OneMinusSrcAlpha);
//            GL.Enable(All.Blend);
//            CheckGLError();
//            //GL.Enable(All.Multisample);
//            //GL.Enable(All.PolygonSmooth);

//            GL.Viewport(0, 0, (int)(width * dpiScale), (int)(height * dpiScale));
//            CheckGLError();
//        }

//        private unsafe void LoadShader(string source, ShaderType type, int program, out int address)
//        {
//            address = GL.CreateShader(type);
//            GL.ShaderSource(address, source);
//            GL.CompileShader(address);
//            GL.AttachShader(program, address);
//            var info = GL.GetShaderInfoLog(address);
//        }

//        public void UpdateViewport()
//        {
//            if (mviewdata == null)
//            {
//                mviewdata = new Matrix4[1];
//            }

//            mviewdata[0] = Matrix4.CreateOrthographicOffCenter(0, RenderWidth, RenderHeight, 0, -1, 1);
//        }

//        private RectangleSpriteBatchItem GetSpriteBatchItem()
//        {
//            RectangleSpriteBatchItem item;
//            int oldCount = m_spriteBatchItemsOld.Count;
//            if (oldCount > 0)
//            {
//                item = m_spriteBatchItemsOld[oldCount - 1];
//                m_spriteBatchItems.Add(item);
//                m_spriteBatchItemsOld.RemoveAt(oldCount - 1);
//            }
//            else
//            {
//                // Create new item.
//                item = new RectangleSpriteBatchItem();
//                m_spriteBatchItems.Add(item);
//            }

//            mReadyItems.Add(item);

//            return item;
//        }

//        private LineSpriteBatchItem GetLineSpriteBatchItem()
//        {
//            LineSpriteBatchItem item;
//            int oldCount = m_spriteBatchItemsOld_line.Count;
//            if (oldCount > 0)
//            {
//                item = m_spriteBatchItemsOld_line[oldCount - 1];
//                m_spriteBatchItems_line.Add(item);
//                m_spriteBatchItemsOld_line.RemoveAt(oldCount - 1);
//            }
//            else
//            {
//                // Create new item.
//                item = new LineSpriteBatchItem();
//                m_spriteBatchItems_line.Add(item);
//            }

//            mReadyItems.Add(item);

//            return item;
//        }

//        private RectangleTrianglesBatchItem GetSTrianglespriteBatchItem()
//        {
//            RectangleTrianglesBatchItem item;
//            int oldCount = m_spriteBatchItemsOld_triangles.Count;
//            if (oldCount > 0)
//            {
//                item = m_spriteBatchItemsOld_triangles[oldCount - 1];
//                m_spriteBatchItems_triangles.Add(item);
//                m_spriteBatchItemsOld_triangles.RemoveAt(oldCount - 1);
//            }
//            else
//            {
//                // Create new item.
//                item = new RectangleTrianglesBatchItem();
//                m_spriteBatchItems_triangles.Add(item);
//            }

//            mReadyItems.Add(item);

//            return item;
//        }

//        private void AddTextureToOpenGL(Texture texture)
//        {
//            Log("Texture adding with id: " + texture.ID);
//            texture.OnEndUpdate += Texture_OnUpdated;

//            int textureId = -1;
//            GL.GenTextures(1, ref textureId);
//            CheckGLError();

//            // 4 = All.Rgba.
//            // GL_RGBA = 0x1908.
//            int Rwidth = (int)SharpDepend.Classes.PeformanceHelper.NearestPowerOfTwo((uint)texture.Width);
//            int Rheight = (int)SharpDepend.Classes.PeformanceHelper.NearestPowerOfTwo((uint)texture.Height);
//            Texture nTexture = texture.IsPowerOfTwo ? texture : texture.Rescale(Rwidth, Rheight); // Use original if po2.
//            int width = nTexture.Width;
//            int height = nTexture.Height;
//            textures_rescaled.Add(texture, nTexture);
            
//            GL.BindTexture(All.Texture2D, textureId);
//            CheckGLError();
//            GL.TexParameter(All.Texture2D, All.TextureMinFilter, (int)All.Nearest);
//            CheckGLError();
//            GL.TexParameter(All.Texture2D, All.TextureMagFilter, (int)All.Linear);
//            CheckGLError();

//            GL.TexImage2D(All.Texture2D, 0, (int)All.Bgra, width, height, 0, All.Bgra, All.UnsignedByte, nTexture.Data);
//            CheckGLError();

//            GL.GenerateMipmap(All.Texture2D);
//            CheckGLError();

//            textures.Add(texture, textureId);
//            Log("Texture added with gl id: " + textureId);
//        }

//        private void RemoveTextureToOpenGL(Texture texture)
//        {
//            texture.OnEndUpdate -= Texture_OnUpdated;

//            int textureId = textures[texture];

//            GL.DeleteTextures(1, ref textureId);

//            textures.Remove(texture);

//            textures_rescaled.Remove(texture);
//        }

//        public void RegisterTexture(Texture texture)
//        {
//            AddTextureToOpenGL(texture);
//        }

//        public void UnregisterTexture(Texture texture)
//        {
//            RemoveTextureToOpenGL(texture);
//        }

//        private void Texture_OnUpdated(Texture texture)
//        {
//            var ntexture = textures_rescaled[texture];
//            texture.Rescale(ntexture);

//            int textureId = textures[texture];
//            GL.BindTexture(All.Texture2D, textureId);
//            CheckGLError();
//            GL.TexSubImage2D(All.Texture2D, 0, 0, 0, ntexture.Width, ntexture.Height, All.Bgra, All.UnsignedByte, ntexture.Data);
//            CheckGLError();
//            GL.TexParameter(All.Texture2D, All.TextureMagFilter, 0x2601);
//            CheckGLError();
//            GL.TexParameter(All.Texture2D, All.TextureMinFilter, 0x2601);
//            CheckGLError();
//        }

//        public void Draw(ref SharpDepend.Datatypes.Vector4 rectangle, SharpDepend.Datatypes.Color color, Texture texture, ref SharpDepend.Datatypes.Vector4 destinationTextureUV)
//        {
//            SharpDepend.Datatypes.Vector4 destinationTextureUV_ = destinationTextureUV;
//            if (rectangle.Width < 0 || rectangle.Height < 0 ||
//                rectangle.X2 <= 0 || rectangle.X1 > RenderWidth ||
//                rectangle.Y2 <= 0 || rectangle.Y1 > RenderHeight)
//            {
//                return;
//            }
//            else if (texture != null && (destinationTextureUV.Width == 0 && destinationTextureUV.Height == 0))
//            {
//                destinationTextureUV_ = texture.Dimension;
//            }

//            RectangleSpriteBatchItem item = GetSpriteBatchItem();

//            item.Depth = 9;
//            item.Texture = texture;

//            SharpDepend.Datatypes.Vector4 rect = rectangle;

//            if (texture != null)
//            {
//                item.TexCoordTL = new OpenTK.Vector2((float)(1.0 / texture.Width * destinationTextureUV_.X), (float)(1.0 / texture.Height * destinationTextureUV_.Y));
//                item.TexCoordBR = new OpenTK.Vector2((float)(1.0 / texture.Width * destinationTextureUV_.X2), (float)(1.0 / texture.Height * destinationTextureUV_.Y2));

//                // TODO: Temporary.
//                if (!textures.ContainsKey(texture))
//                {
//                    item.TextureID = -1;
//                }
//                else
//                {
//                    item.TextureID = textures[texture];
//                }
//            }

//            item.Texture = texture;

//            item.Color = new OpenTK.Vector4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f);
//            item.vertexTL = new OpenTK.Vector2((float)rectangle.X, (float)rectangle.Y);
//            item.vertexTR = new OpenTK.Vector2((float)rectangle.X2, (float)rectangle.Y);
//            item.vertexBR = new OpenTK.Vector2((float)rectangle.X2, (float)rectangle.Y2);
//            item.vertexBL = new OpenTK.Vector2((float)rectangle.X, (float)rectangle.Y2);
//        }

//        public void DrawCircle(SharpDepend.Datatypes.Vector2 position, double radius, SharpDepend.Datatypes.Color color)
//        {

//        }

//        public void DrawLine(SharpDepend.Datatypes.Vector2 start, SharpDepend.Datatypes.Vector2 end, SharpDepend.Datatypes.Color color)
//        {
//            LineSpriteBatchItem item = GetLineSpriteBatchItem();

//            item.Depth = 9;

//            item.Color = new OpenTK.Vector4(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f);
//            item.Start = new OpenTK.Vector2((float)start.X, (float)start.Y);
//            item.Stop = new OpenTK.Vector2((float)end.X, (float)end.Y);
//        }

//        public void DrawTriangles(IList<SharpDepend.Datatypes.Vector2> vertices, IList<ushort> indices, IList<Color> colors)
//        {
//            RectangleTrianglesBatchItem item = GetSTrianglespriteBatchItem();

//            item.Depth = 10;

//            item.SetVertices(vertices);
//            item.SetIndices(indices);
//            item.SetColors(colors);
//        }

//        public void BeginRender()
//        {
//            GL.Clear((int)(All.ColorBufferBit | All.DepthBufferBit));
//            GL.Enable(All.DepthTest);
//            GL.ClearColor(0.0f, 1.0f, 0.0f, 1.0f); // Black Background
//        }

//        public void Update()
//        {
//            texcoords.Clear();
//            vertdata.Clear();
//            coldata.Clear();
//            inds.Clear();

//            int length = 0;

//            // Draw all items.
//            int count = mReadyItems.Count;
//            for (int i = 0; i < count; i++)
//            {
//                var item = mReadyItems[i];

//                inds.AddRange(item.AddIndices((ushort)vertdata.Count, ref length), ref length);
//                vertdata.AddRange(item.GetVertices(ref length), ref length);
//                coldata.AddRange(item.GetColors(ref length), ref length);
//                texcoords.AddRange(item.GetTextureCoords(ref length), ref length);
//            }

//            //Log("GL draw: " + mReadyItems.Count);

//            // =====================================================
//            // Buffer vertex coordinates.
//            GL.BindBuffer(All.ArrayBuffer, vbo_position);
//            GL.BufferData<float>(All.ArrayBuffer, (IntPtr)(vertdata.Count * sizeof(float)), vertdata.ToArray(), All.StaticDraw);
//            GL.VertexAttribPointer(attribute_vpos, 2, All.Float, false, 0, IntPtr.Zero);
//            var error = GL.GetError();

//            // Buffer colors coords.
//            GL.BindBuffer(All.ArrayBuffer, vbo_color);
//            GL.BufferData<float>(All.ArrayBuffer, (IntPtr)(coldata.Count * sizeof(float)), coldata.ToArray(), All.StaticDraw);
//            GL.VertexAttribPointer(attribute_vcol, 4, All.Float, true, 0, IntPtr.Zero);

//            // Buffer texture coords.
//            GL.BindBuffer(All.ArrayBuffer, vbo_texcoord);
//            GL.BufferData<float>(All.ArrayBuffer, (IntPtr)(texcoords.Count * sizeof(float)), texcoords.ToArray(), All.StaticDraw);
//            GL.VertexAttribPointer(attribute_texcoord, 2, All.Float, true, 0, IntPtr.Zero);
//            error = GL.GetError();

//            GL.BindBuffer(All.ArrayBuffer, 0);
//            error = GL.GetError();

//            GL.BindBuffer(All.ElementArrayBuffer, ibo_elements);
//            GL.BufferData(All.ElementArrayBuffer, (IntPtr)(inds.Count * sizeof(uint)), inds.ToArray(), All.StaticDraw);
//            error = GL.GetError();
//        }

//        public void EndRender()
//        {
//            // =====================================================
//            GL.UseProgram(pgmID);

//            GL.EnableVertexAttribArray(attribute_vpos);
//            GL.EnableVertexAttribArray(attribute_vcol);
//            GL.EnableVertexAttribArray(attribute_texcoord);
//            var error = GL.GetError();

//            int count = mReadyItems.Count;
//            int offset = 0;
//            for (int i = 0; i < count; i++)
//            {
//                var item = mReadyItems[i];
//                int indices = item.Indices;

//                GL.ActiveTexture(All.Texture0);
//                error = GL.GetError();

//                if (item.Texture == null)
//                {
//                    GL.BindTexture(All.Texture2D, textures[defaultTexture]);
//                }
//                else
//                {
//                    GL.BindTexture(All.Texture2D, item.TextureID);
//                }

//                error = GL.GetError();

//                float huh = mviewdata[0].Determinant;
//                GL.UniformMatrix4(uniform_mview, 1, false, ref huh);

//                error = GL.GetError();
//                GL.DrawElements(All.Triangles, indices, All.UnsignedShort, (IntPtr)(offset * sizeof(ushort)));
//                offset += indices;
//                error = GL.GetError();
//            }

//            GL.DisableVertexAttribArray(attribute_vpos);
//            GL.DisableVertexAttribArray(attribute_vcol);
//            GL.DisableVertexAttribArray(attribute_texcoord);

//            GL.Flush();
//            error = GL.GetError();
//            ClearBatchItems();
//        }

//        public void ClearBatchItems()
//        {
//            m_spriteBatchItemsOld.AddRange(m_spriteBatchItems);
//            m_spriteBatchItems.Clear();
//            m_spriteBatchItemsOld_line.AddRange(m_spriteBatchItems_line);
//            m_spriteBatchItems_line.Clear();
//            m_spriteBatchItemsOld_triangles.AddRange(m_spriteBatchItems_triangles);
//            m_spriteBatchItems_triangles.Clear();
//            mReadyItems.Clear();
//        }

//        public float RenderWidth { get; set; }

//        public float RenderHeight { get; set; }
//    }
//}